package cn.com.lyb.workflow.service.impl;

import cn.com.lyb.asyncTask.construnctor.AsyncTaskConstructor;
import cn.com.lyb.asyncTask.manage.AsyncTaskManager;
import cn.com.lyb.core.constant.Constants;
import cn.com.lyb.core.exception.BizException;
import cn.com.lyb.job.dao.JobInstanceDao;
import cn.com.lyb.job.entity.JobInstanceDO;
import cn.com.lyb.workflow.dao.*;
import cn.com.lyb.workflow.entity.*;
import cn.com.lyb.workflow.entity.dto.ConditionResultDTO;
import cn.com.lyb.workflow.entity.dto.SaveWorkflowDTO;
import cn.com.lyb.workflow.entity.dto.TaskRelation;
import cn.com.lyb.workflow.entity.dto.WorkflowJobDTO;
import cn.com.lyb.workflow.service.IWorkflowService;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 工作流 服务实现类
 * </p>
 *
 * @author lvyuanbo
 * @since 2024-07-9
 */
@Service
public class WorkflowServiceImpl extends ServiceImpl<WorkflowDao, WorkflowDO> implements IWorkflowService {
    private static final Logger logger = LoggerFactory.getLogger(WorkflowServiceImpl.class);

    //状态  未开始  2 进行中 3 成功 4 失败 5 暂停
    private static final String NOSTART = "1";
    private static final String RUNNING = "2";
    private static final String SUCCESS = "3";
    private static final String FAIL = "4";
    private static final String PAUSE = "5";



    @Autowired
    private WorkflowInstanceDao workflowInstanceDao;

    @Autowired
    private WorkflowDao workflowDao;

    @Autowired
    private WorkflowJobDao workflowJobDao;

    @Autowired
    private WorkflowInstanceSnapDao workflowInstanceSnapDao;

    @Autowired
    private AsyncTaskManager asyncTaskManager;

    @Autowired
    private JobInstanceDao jobInstanceDao;
    
    @Autowired
    private WorkflowDependencyDao workflowDependencyDao;


    /**
     * 运行工作流
     *
     * @param workflowId
     */
    @Override
    public void startWorkflow(Long workflowId) {
        WorkflowDO workflowDO = getById(workflowId);
        // 先插总历史记录
        WorkflowInstanceDO workflowInstanceDO = new WorkflowInstanceDO();
        workflowInstanceDO.setWorkflowId(workflowId);
        workflowInstanceDO.setStatus(RUNNING);
        workflowInstanceDao.insert(workflowInstanceDO);
        Long workflowInstanceId = workflowInstanceDO.getId();
        // 插入快照
        WorkflowInstanceSnapDO snapDO = new WorkflowInstanceSnapDO();
        snapDO.setWorkflowInstanceId(workflowInstanceId);
        snapDO.setLocationJson(workflowDO.getLocationJson());
        snapDO.setRelationJson(workflowDO.getRelationJson());
        snapDO.setTaskJson(workflowDO.getTaskJson());
        workflowInstanceSnapDao.insert(snapDO);
        // 添加任务
        LambdaQueryWrapper<WorkflowJobDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkflowJobDO::getWorkflowId, workflowDO.getId());
        queryWrapper.eq(WorkflowJobDO::getDel, Constants.IS_NOT_DEL);
        List<WorkflowJobDO> list = workflowJobDao.selectList(queryWrapper);
        List<JobInstanceDO> jobInstanceDOList = new ArrayList<>();
        for (WorkflowJobDO workflowJobDO : list) {
            JobInstanceDO jobInstanceDO = new JobInstanceDO();
            jobInstanceDO.setStatus(NOSTART);
            jobInstanceDO.setWorkflowInstanceId(workflowInstanceId);
            jobInstanceDO.setJobId(workflowJobDO.getJobId());
            jobInstanceDO.setCode(workflowJobDO.getCode());
            jobInstanceDO.setStartTime(new Date());
            jobInstanceDOList.add(jobInstanceDO);
        }
        jobInstanceDao.insertBatchSomeColumn(jobInstanceDOList);
        // 添加关系
        String relationJson = workflowDO.getRelationJson();
        List<TaskRelation> taskRelationList = JSONUtil.toList(relationJson, TaskRelation.class);
        List<WorkflowDependencyDO> workflowDependencyDOList = new ArrayList<>();
        for (TaskRelation taskRelation : taskRelationList) {
            WorkflowDependencyDO workflowDependencyDO = new WorkflowDependencyDO();
            workflowDependencyDO.setWorkflowInstanceId(workflowInstanceId);
            workflowDependencyDO.setPreTaskCode(taskRelation.getPreTaskCode());
            workflowDependencyDO.setPostTaskCode(taskRelation.getPostTaskCode());
            workflowDependencyDO.setType("1");
            workflowDependencyDOList.add(workflowDependencyDO);
            WorkflowDependencyDO workflowDependencyDO1 = new WorkflowDependencyDO();
            workflowDependencyDO1.setWorkflowInstanceId(workflowInstanceId);
            workflowDependencyDO1.setPreTaskCode(taskRelation.getPostTaskCode());
            workflowDependencyDO1.setPostTaskCode(taskRelation.getPreTaskCode());
            workflowDependencyDO1.setType("2");
            workflowDependencyDOList.add(workflowDependencyDO1);
        }
        workflowDependencyDao.insertBatchSomeColumn(workflowDependencyDOList);

        executeWorkflow(0L, workflowInstanceId, workflowId);
        workflowInstanceDO.setStatus(SUCCESS);
        workflowInstanceDao.updateById(workflowInstanceDO);

    }

    public void executeWorkflow(Long startTaskCode, Long workflowInstanceId, Long workflowId) {
        LambdaQueryWrapper<WorkflowDependencyDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WorkflowDependencyDO::getWorkflowInstanceId, workflowInstanceId);
        queryWrapper.eq(WorkflowDependencyDO::getType, "2");
        List<WorkflowDependencyDO> list = workflowDependencyDao.selectList(queryWrapper);
        Map<Long, List<Long>> reverseDependencyMap = new HashMap<>();
        for (WorkflowDependencyDO workflowDependencyDO : list) {
            reverseDependencyMap.putIfAbsent(workflowDependencyDO.getPreTaskCode(), new ArrayList<>());
            reverseDependencyMap.get(workflowDependencyDO.getPreTaskCode()).add(workflowDependencyDO.getPostTaskCode());
        }
        LambdaQueryWrapper<WorkflowDependencyDO> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(WorkflowDependencyDO::getWorkflowInstanceId, workflowInstanceId);
        queryWrapper1.eq(WorkflowDependencyDO::getType, "1");
        List<WorkflowDependencyDO> list1 = workflowDependencyDao.selectList(queryWrapper);
        Map<Long, List<Long>> dependencyMap = new HashMap<>();
        for (WorkflowDependencyDO workflowDependencyDO : list1) {
            dependencyMap.putIfAbsent(workflowDependencyDO.getPostTaskCode(), new ArrayList<>());
            dependencyMap.get(workflowDependencyDO.getPostTaskCode()).add(workflowDependencyDO.getPreTaskCode());
        }
        Set<Long> executedTasks = new HashSet<>();
        Queue<Long> queue = new LinkedList<>();
        queue.offer(startTaskCode);
        while (!queue.isEmpty()) {
            Long taskCode = queue.poll();
            if (executedTasks.contains(taskCode) || !canExecute(taskCode, reverseDependencyMap, executedTasks)) {
                logger.info("已经执行过，或者该任务不能执行");
                continue;
            }
            LambdaQueryWrapper<WorkflowJobDO> queryWrapper2 = new LambdaQueryWrapper<>();
            queryWrapper2.eq(WorkflowJobDO::getCode, taskCode);
            queryWrapper2.eq(WorkflowJobDO::getWorkflowId, workflowId);
            queryWrapper2.eq(WorkflowJobDO::getDel, Constants.IS_NOT_DEL);
            WorkflowJobDO workflowJobDO = workflowJobDao.selectOne(queryWrapper2);
            logger.info("执行任务信息:{}", workflowJobDO);
            Boolean success = true;
            if(!workflowJobDO.getType().equals("4")){
                success = executeTask(workflowJobDO.getJobId(), workflowInstanceId);
            }
            executedTasks.add(taskCode);
            if (workflowJobDO.getType().equals("3")) {
                List<Long> nextTasks =
                        success ? workflowJobDO.getConditionResult().getSuccessNode() : workflowJobDO.getConditionResult().getFailedNode();
                if (nextTasks != null) {
                    queue.addAll(nextTasks);
                }
            } else {
                List<Long> nextTasks = dependencyMap.get(taskCode);
                if (nextTasks != null) {
                    queue.addAll(nextTasks);
                }
            }
        }
    }

    private Boolean executeTask(Long jobId, Long workflowInstanceId) {
        logger.info("假装执行任务开始");
        LambdaQueryWrapper<JobInstanceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JobInstanceDO::getJobId, jobId);
        queryWrapper.eq(JobInstanceDO::getWorkflowInstanceId, workflowInstanceId);
        JobInstanceDO jobInstanceDO = jobInstanceDao.selectOne(queryWrapper);
        jobInstanceDO.setEndTime(new Date());
        jobInstanceDO.setStatus(SUCCESS);
        jobInstanceDao.updateById(jobInstanceDO);
        logger.info("假装执行任务结束");
        return true;
    }

    private boolean canExecute(Long taskCode, Map<Long, List<Long>> reverseDependencyMap, Set<Long> executedTasks) {
        List<Long> preTasks = reverseDependencyMap.get(taskCode);
        if (preTasks == null) {
            return true;
        }
        for (Long preTaskId : preTasks) {
            if (!executedTasks.contains(preTaskId)) {
                return false;
            }
        }
        return true;
    }






    class AsyncFlowworkRunConstructor implements AsyncTaskConstructor{
        private WorkflowDO workflowDO;

        private Long workflowInstanceId;

        public AsyncFlowworkRunConstructor(WorkflowDO workflowDO, Long workflowInstanceId) {
            this.workflowDO = workflowDO;
            this.workflowInstanceId = workflowInstanceId;
        }

        /**
         * 异步执行方法
         */
        @Override
        public void async() {
        }



        /**
         * 成功回调方法
         */
        @Override
        public void callBackAfterSuccess() {

        }

        /**
         * 失败回调方法
         *
         * @param throwable
         */
        @Override
        public void callBackAfterFail(Throwable throwable) {

        }
    }

    /**
     * 保存工作流
     *
     * @param saveWorkflowDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveEntity(SaveWorkflowDTO saveWorkflowDTO) {
        WorkflowDO workflowDO = new WorkflowDO();
        workflowDO.setDel(Constants.IS_NOT_DEL);
        workflowDO.setName(saveWorkflowDTO.getName());
        workflowDO.setDescription(saveWorkflowDTO.getDescription());
        workflowDO.setLocationJson(saveWorkflowDTO.getLocations().toString());
        workflowDO.setRelationJson(saveWorkflowDTO.getTaskRelations().toString());
        workflowDO.setTaskJson(saveWorkflowDTO.getTaskDTOList().toString());
        workflowDao.insert(workflowDO);
        Long workflowDOId = workflowDO.getId();
        List<WorkflowJobDO> workflowJobDOList = new ArrayList<>();
        List<WorkflowJobDTO> taskDTOList = saveWorkflowDTO.getTaskDTOList();
        for(WorkflowJobDTO workflowJobDTO : taskDTOList) {
            WorkflowJobDO workflowJobDO = new WorkflowJobDO();
            workflowJobDO.setDel(Constants.IS_NOT_DEL);
            workflowJobDO.setCode(workflowJobDTO.getCode());
            workflowJobDO.setJobName(workflowJobDTO.getJobName());
            workflowJobDO.setJobId(workflowJobDTO.getJobId());
            workflowJobDO.setType(workflowJobDTO.getType());
            workflowJobDO.setWorkflowId(workflowDOId);
            if(workflowJobDTO.getType().equals("3")) {
                workflowJobDO.setConditionResult(workflowJobDTO.getConditionResult());
            }
            workflowJobDOList.add(workflowJobDO);
        }
        workflowJobDao.insertBatchSomeColumn(workflowJobDOList);
    }



}
